﻿using System;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using Microsoft.Win32;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.BizTalk.Adapter.Framework;
using System.Xml.XPath;
using System.Xml.Serialization;

namespace Sixeyed.CacheAdapter.Management
{
    /// <summary>
    /// Management class for Cache adapter
    /// </summary>
    public class AdapterManagement : IStaticAdapterConfig, IAdapterConfig, IAdapterConfigValidation, IAdapterInfo
	{																																		  
		/// <summary>
        /// Returns the TransmitLocation configuration schema as a string
        /// </summary>
        /// <param name="configType">Configuration type</param>
        /// <returns>TransmitLocation schema as string, null for other ConfigType values</returns>
        public string GetConfigSchema(ConfigType configType) 
		{
            string schema = null;
            switch (configType) 
			{
				case ConfigType.TransmitLocation:
                    schema = GetResource(Resource.TransmitLocationSchema);
                    break;
			}
            return schema;
        }

        /// <summary>
        /// Gets the help topic ID for the adapter
        /// </summary>
        /// <remarks>
        /// Not implemented
        /// </remarks>
        /// <param name="configType">Configuration type</param>
        /// <returns>Null</returns>
        public string GetHelpString(ConfigType configType)
        {
            return null;
        }

        /// <summary>
		/// Get the WSDL file name for the selected WSDL
        /// </summary>
        /// <remarks>
        /// Not implemented
        /// </remarks>
        /// <param name="wsdls">place holder</param>
        /// <returns>Null</returns>
        public string[] GetServiceDescription(string[] wsdls) 
		{
            return null;
        }

        /// <summary>
        /// This function is called by the add generated items functionality in 
		/// BizTalk (rightclick BizTalk project in VS, Add, etc.) 
		/// Gets the XML instance of TreeView that needs to be rendered
        /// </summary>
        /// <remarks>
        /// Not implemented
        /// </remarks>
        /// <param name="endPointConfiguration"></param>
        /// <param name="NodeIdentifier"></param>
        /// <returns>TreeView xml instance</returns>
        public string GetServiceOrganization(IPropertyBag endPointConfiguration, string NodeIdentifier)
		{
            return null;
        }

        /// <summary>
        /// Acquire externally referenced xsd's
        /// </summary>
        /// <remarks>
        /// Not implemented
        /// </remarks>
        /// <param name="xsdLocation">Location of schema</param>
        /// <param name="xsdNamespace">Namespace</param>
        /// <param name="xsdSchema">Schema file name (returned as null)</param>
        /// <returns>Result.Continue</returns>
        public Result GetSchema(string xsdLocation, string xsdNamespace, out string xsdSchema) 
		{
            xsdSchema = null;
            return Result.Continue;
        }

        /// <summary>
        /// Validate xmlInstance against configuration.  In this example it does nothing.
        /// </summary>
        /// <param name="configType">Type of port or location being configured</param>
        /// <param name="xmlInstance">Instance value to be validated</param>
        /// <returns>Validated configuration</returns>
        public string ValidateConfiguration(ConfigType configType, string xmlInstance) 
		{
            string validXml = String.Empty;

            switch (configType) 
			{
				case ConfigType.TransmitLocation:
					validXml = ValidateTransmitLocation(xmlInstance); 
                    //if valid, wizard is ending - clear out the current config:
                    TransmitLocation.Current = null;
					break;
            }

            return validXml;
        }

        private string GetResource(string resource) 
		{
            string value = null;
            if (null != resource) 
			{
				Assembly assem = this.GetType().Assembly;
				Stream stream = assem.GetManifestResourceStream(resource);
				StreamReader reader = null;

                using (reader = new StreamReader(stream)) 
				{
                    value = reader.ReadToEnd();
                }
            }

            return value;
        }

        private string ValidateTransmitLocation(string configXml) 
		{
            //the namespace is not provided in the XML, so use
            //XPath to validate rather than deserializing:
            XmlDocument configDocument = new XmlDocument();
            configDocument.LoadXml(configXml);

            string name = Extract(configDocument, "name");
            string provider = Extract(configDocument, "provider");
            string configuration = Extract(configDocument, "configuration");

            if (string.IsNullOrEmpty(name))
            {
                throw new Exception("Cache Name is required");
            }
            if (string.IsNullOrEmpty(provider))
            {
                throw new Exception("Cache Provider is required");
            }
            if (string.IsNullOrEmpty(configuration))
            {
                throw new Exception("Cache Provider Configuration is required");
            }

            //uri format - "cache://providerTypeName/name":
            XmlNode uriNode = configDocument.SelectSingleNode("/Config/uri");
            if (uriNode == null)
            {
                uriNode = configDocument.CreateElement("uri");
                configDocument.DocumentElement.InsertBefore(uriNode, configDocument.DocumentElement.FirstChild);
            }
            UriBuilder uriBuilder = new UriBuilder();
            Type providerType = Type.GetType(provider);
            uriBuilder = new UriBuilder("cache", providerType.Name);
            uriBuilder.Path = name;
            uriNode.InnerText = uriBuilder.ToString();

            return configDocument.OuterXml;
        }

        private string Extract(XmlDocument configDocument, string elementName)
        {
            string value = string.Empty;
            XmlNode node = configDocument.SelectSingleNode(string.Format("/Config/{0}", elementName));
            if (node != null)
            {
                value = node.InnerText;
            }
            return value;
        }

        private struct Resource
        {
            /// <summary>
            /// "Sixeyed.CacheAdapter.Management.TransmitLocation.xsd"
            /// </summary>
            public const string TransmitLocationSchema = "Sixeyed.CacheAdapter.Management.TransmitLocation.xsd";
        }
	} 
}